/*
 * Copyright 2011 Mark Davidson.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package org.dctmcommons.impl;

import java.util.ArrayList;
import java.util.List;

import org.dctmcommons.IParamCheck;
import org.dctmcommons.IQueryHelper;
import org.dctmcommons.ITeardownBuilder;

import com.documentum.fc.client.IDfCollection;
import com.documentum.fc.client.IDfFolder;
import com.documentum.fc.client.IDfQuery;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.common.DfDocbaseConstants;
import com.documentum.fc.common.DfException;
import com.documentum.fc.common.DfLogger;

/**
 * Default implementation of {@link ITeardownBuilder}
 * @author Mark Davidson
 */
public class TeardownBuilder implements ITeardownBuilder {

    /** Key for path token. */
    private static final String TOKEN_PATH = "PATH";

    /** DQL for removing all documents within the folder structure. */
    private static final String DQL_REMOVE_DOCS =
    	"delete dm_document (all) objects " +
    	"where folder('" + TOKEN_PATH + "', descend)";
    
    /** DQL for removing all virtualdocs within the folder structure. */
    private static final String DQL_REMOVE_VDOCS =
    	"delete dm_document (all) objects " +
    	"where folder('" + TOKEN_PATH + "', descend) " +
    	"and (r_is_virtual_doc = 1 or r_link_cnt > 0)";

    /** DQL for getting all folders within the folder structure. */
    private static final String DQL_GET_SUB_FOLDERS =
    	"select r_folder_path " +
    	"from dm_folder " +
    	"where folder('" + TOKEN_PATH +"',descend) " +
    	"order by r_folder_path desc";

	/** Include snapshots flag. */
	private boolean includeSnapshots = false;
	
	/** Include virtual docs flag. */
	private boolean includeVirtualDocs = false;
	
	/** Include documents flag. */
	private boolean includeDocuments = false;
	
	/** Include folders flag. */
	private boolean includeFolders = false;
	
	/** Include base folder flag. */
	private boolean includeBaseFolder = false;
	
	/** The base path. */
	private String basePath = null;
	
	/** The query helper. */
	private IQueryHelper qh = QueryHelper.getInstance();
	
	/** The param check. */
	private IParamCheck paramCheck = ParamCheck.getInstance();
	
	/**
	 * Default constructor.
	 */
	private TeardownBuilder(final String basePath) {
		paramCheck.checkString(basePath, "basePath");
		this.basePath = basePath;
	}
	
	/**
	 * Factory method.
	 * @param basePath The base path
	 * @return A TeardownBuilder instance
	 */
	public static ITeardownBuilder from(final String basePath) {
		return new TeardownBuilder(basePath);
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.dctmcommons.ITeardownBuilder#includeAllChildObjects()
	 */
	@Override
	public ITeardownBuilder includeAllChildObjects() {
		includeBaseFolder = false;
		includeDocuments = true;
		includeFolders = true;
		includeSnapshots = true;
		includeVirtualDocs = true;
		return this;
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.dctmcommons.ITeardownBuilder#includeAllObjects()
	 */
	@Override
	public ITeardownBuilder includeAllObjects() {
		includeBaseFolder = true;
		includeDocuments = true;
		includeFolders = true;
		includeSnapshots = true;
		includeVirtualDocs = true;
		return this;
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.dctmcommons.ITeardownBuilder#includeBaseFolder()
	 */
	@Override
	public ITeardownBuilder includeBaseFolder() {
		includeBaseFolder = true;
		return this;
	}
	
	/*
	 * (non-Javadoc)
	 * @see org.dctmcommons.ITeardownBuilder#includeSnapshots()
	 */
	@Override
	public ITeardownBuilder includeSnapshots() {
		includeSnapshots = true;
		return this;
	}

	/*
	 * (non-Javadoc)
	 * @see org.dctmcommons.ITeardownBuilder#includeVirtualDocs()
	 */
	@Override
	public ITeardownBuilder includeVirtualDocs() {
		includeVirtualDocs = true;
		return this;
	}

	/*
	 * (non-Javadoc)
	 * @see org.dctmcommons.ITeardownBuilder#includeDocuments()
	 */
	@Override
	public ITeardownBuilder includeDocuments() {
		includeDocuments = true;
		return this;
	}

	/*
	 * (non-Javadoc)
	 * @see org.dctmcommons.ITeardownBuilder#includeFolders()
	 */
	@Override
	public ITeardownBuilder includeFolders() {
		includeFolders = true;
		return this;
	}

	/*
	 * (non-Javadoc)
	 * @see org.dctmcommons.ITeardownBuilder#teardown(com.documentum.fc.client.IDfSession)
	 */
	@Override
	public void build(final IDfSession session) throws DfException {
		paramCheck.checkObject(session, "session");
		
		if (includeSnapshots) {
			// TODO
		}
		
		if (includeVirtualDocs) {
			removeVirtualDocuments(session);
		}
		
		if (includeDocuments) {
			removeDocuments(session);
		}
		
		if (includeFolders) {
			removeSubFolders(session);
		}
		
		if (includeBaseFolder) {
			removeFolderByPath(session, basePath);
		}
	}
	
    /**
     * Destroys the virtual documents.
     * @param session The session
     * @throws DfException The repository exception
     */
    private void removeVirtualDocuments(final IDfSession session)
    	throws DfException {
    	final String dql = DQL_REMOVE_VDOCS.replaceFirst(TOKEN_PATH,
														 basePath);
    	qh.updateQuery(session, dql, IDfQuery.DF_EXEC_QUERY);
    }

    /**
     * Destroys the documents.
     * @param session The session
     * @throws DfException The repository exception
     */
    private void removeDocuments(final IDfSession session)
    	throws DfException {
    	final String dql = DQL_REMOVE_DOCS.replaceFirst(TOKEN_PATH,
														basePath);
    	qh.updateQuery(session, dql, IDfQuery.DF_EXEC_QUERY);
    }

	/**
	 * Removes sub-folders.
	 * @param session The session
	 * @throws DfException The repository exception
	 */
	private void removeSubFolders(final IDfSession session) throws DfException {
		// remove sub-folders
    	final String dql = DQL_GET_SUB_FOLDERS.replaceFirst(
												TOKEN_PATH,
												basePath);
    	final IDfCollection results = qh.query(session,
											   dql,
											   IDfQuery.DF_READ_QUERY);
    	
    	final List<String> paths = new ArrayList<String>();
    	
    	if (results != null) {
    		while (results.next()) {
    			final String path =
    					results.getRepeatingString(
								DfDocbaseConstants.R_FOLDER_PATH, 0);
    			paths.add(path);
    		}
    	}
    	
    	// remove test sub-folders
    	for (final String path : paths) {
    		if (path != null &&
    				path.trim().length() > 1) {
    			if (DfLogger.isTraceEnabled(this)) {
					   DfLogger.trace(this, "Getting sub-folder: " + path,
							   		  null, null);
    			}
    			final IDfFolder folder = session.getFolderByPath(path);
    			folder.destroy();
    			if (DfLogger.isDebugEnabled(this)) {
    				DfLogger.debug(this, "Destroyed sub-folder", null, null);
    			}
    		}
    	}

	}
	
    /**
     * Destroys the folder at the specified path.
     * @param session The session
     * @param folderPath The folder path
     * @throws DfException The repository exception
     */
    public void removeFolderByPath(final IDfSession session,
    							   final String folderPath)
    	throws DfException {
    	getFolderByPath(session, folderPath).destroy();
    }
    
    /**
     * Gets the folder at the specified path.
     * @param session The session
     * @param folderPath The folder path
     * @return The folder
     * @throws DfException The repository exception
     */
    public IDfFolder getFolderByPath(final IDfSession session,
    								 final String folderPath)
    	throws DfException {
    	return session.getFolderByPath(folderPath);
    }
}
